﻿using System;
using System.Collections.Generic;
using Flatland.GeneticProgramming.CoreTypes;
using Flatland.GeneticProgramming.Initializations;
using Flatland.GeneticProgramming.SyntaxTree;
using Flatland.Utilities;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneticProgramming.Mutations {
    /// <summary>
    /// Subtree mutation class
    /// </summary>
    class SubtreeMutation : IMutation {
        /// <summary>
        /// Grows a new subtree at max the depth of mutated node
        /// </summary>
        /// <param name="reports"></param>
        /// <param name="mutationRate"></param>
        public void Mutate(List<Report> reports, double mutationRate, int maxTreeDepth) {
            foreach (var report in reports) {
                if ((double)Utils.Random.Next(101) / 100 <= mutationRate) {
                    var node = report.GenoType.Tree.GetRandomNode();
                    if (node.Parent == null) continue;
                    PrimitiveSet primitiveSet = report.PrimitiveSet;
                    if (!node.IsCommandSet())
                        primitiveSet = report.PrimitiveSet.TypedSet();
                    if(primitiveSet.TerminalSet.Count == 0)
                       Console.WriteLine("No terminals found");
                    var sub = new Initialization(InitializationTechnique.Grow).Init((uint)(maxTreeDepth - node.Depth()), primitiveSet);
                    if(node.Equals(sub))
                        ((Node)node.Parent).Replace(node, sub);
                }
                if (UserPreferences.VERBOSE)
                    Console.WriteLine("Subtree mutation was ignored with rate {0}", mutationRate);
            }
        }
    }
}
